package edu.unc.comp410.colemangeer.model;

import static java.lang.System.out;
import java.util.*;

import org.apache.log4j.Logger;
import edu.unc.comp410.colemangeer.model.constraints.IConstraint;
import edu.unc.comp410.colemangeer.model.object.PersistentObject;

/**
 *  A Product for sale.
 * @author ccoleman
 * 
 * ---The price of any product is >= $1.00 and <= $100,000.00
 */
public class Product extends PersistentObject implements IConstraint, ISellable {
	
	private static Logger log = Logger.getLogger(Product.class);
	
	private static final String SEP = "|"; // Field separator in String
	private static final String REGEX_SEP = "\\" + SEP;
	private static final String CAT_SEP = ","; // separator in the DB category field
	private static final String REGEX_CAT_SEP = CAT_SEP;
	private static final int NUM_FIELDS = 3;
	
	
	/**
	 * Persistent object data fields
	 */
	// ID is handled by the superclass
	private final String productName;
	private final Double price;
	private final EnumSet<ProductCategory> productCategories;
	private Integer warehouse;
	private List<ProductCategory> constructCat;
	

	//TODO: make public interface for persistent fields
	
	/**
	 * Public constructors
	 * 
	 * TODO: all params are required
	 */
	public Product(Integer id, String productName, Double price, List<ProductCategory> categories) {
		
		super(id);
		
		if (productName == null || price == null || categories == null)
			throw new NullPointerException();
		
		if (price < Double.valueOf(1) || price > Double.valueOf(100000)) {
			throw new IllegalArgumentException();
		} 
		
		this.constructCat = categories;
		this.productName = productName;
		this.price = price;
		this.productCategories = ProductCategory.buildCategorySet(categories);
	}
	
	public List<ProductCategory> getConstructCat(){
		return constructCat;
	}

	public Integer getWarehouse(){
		return warehouse;
	}
	
	public void setWarehouse( Integer theInt ){
		warehouse = theInt;
	}
	
	/**
	 * Convert a String representation into a Product
	 */
	public static Product buildFromString(String str) {
		//log.info("Building Product from string: " + str);
		
		String[] field = str.split(REGEX_SEP);
	
		// check the sum of superclass' Id field + this classes data fields
		// against the number of fields in the string
		if (PersistentObject.getNumberOfDataFields() + NUM_FIELDS != field.length)
			throw new IllegalArgumentException();
		
		Integer theProdId = Integer.parseInt(field[0]);
		String theName = field[1];
		
		Double thePrice = Double.parseDouble(field[2]);
		List<String> categories = new ArrayList<String>();
		
		//make ProductCategories out of the words in the category field
		String[] catField = field[3].split(REGEX_CAT_SEP);
		if ( catField.length < 1 )
			throw new IllegalArgumentException();
		
		categories = Arrays.asList(catField);
		
		return new Product(theProdId, theName,
				thePrice, ProductCategory.buildCategoryList(categories));
	}

	public Integer getProductID(){
		return getId();
	}

	/**
	 * Getters and Setters
	 */
	public String getName() {
		return productName;
	}

	public Double getPrice() {
		return price;
	}

	/** method to convert dollars (double) into cents (Integer)
	 * 
	 */
	
	public Set<ProductCategory> getProductCategories() {
		return productCategories;
	}

	/**
	 * @return comma separated list of this product's
	 * product categories
	 */
	public String getCategoryString(){
		
		StringBuilder result = new StringBuilder();
		boolean needsComma = false;
		
		for (ProductCategory c : productCategories){
			if (needsComma){
				result.append(", ");
			}
			else{
				needsComma = true;
			}
			result.append(c.toString());
		}
		return result.toString();
	}

	// returning List of products like CatalogItem does,
	// conforming to the ISellable interface.
	

	public List<Product> getAllProducts() {
		ArrayList<Product> products = new ArrayList<Product>();
		products.add(this);
		return Collections.unmodifiableList(products);
	}

	/**
	 * Inherited methods
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Object clone() throws CloneNotSupportedException {
		return new Product(getId(),getName(),getPrice(), 
				Collections.list((Enumeration<ProductCategory>) getProductCategories()));
	}


	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Product))
			return false;
		Product compareProduct = (Product) obj;
		
		return  this.getId().equals(compareProduct.getId())
		&& this.getName().equals(compareProduct.getName())
		&& this.getPrice().equals(compareProduct.getPrice())
		&& this.getProductCategories().equals(compareProduct.getProductCategories());
			
	}

	@Override
	public int hashCode() {
		int result = 17;
		result = (int) (31 * result + this.price); //TODO: use Bloch's method for Double
		result = 31 * result + this.getId().intValue();
		result = 31 * result + this.getName().hashCode();
		result = 31 * result + this.getProductCategories().hashCode();
		return result;
	}

	@Override
	public String toString() {

		StringBuilder result = new StringBuilder(getId());
		result.append("|").append(getName())
		.append("|").append(getPrice())
		.append("|").append(getCategoryString()).append("|");
		
		return result.toString();
	}

	@Override
	public String getConstraintName() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isLegal(Object theObject) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void validate(Object theObject) throws IllegalStateException {
		// TODO Auto-generated method stub

	}
}
